package com.mazaiting.classfile.attr;

import com.mazaiting.classfile.ClassReader;
import com.mazaiting.classfile.attr.info.AttributeInfo;
import com.mazaiting.classfile.attr.info.CodeAttribute;
import com.mazaiting.classfile.attr.info.ConstantValueAttribute;
import com.mazaiting.classfile.constant.ConstantPool;
import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 成员信息
 * 分别存储字段和方法信息。字段和方法的基本结构大致相同，差别仅在于属性表
 * @author mazaiting
 * @since 2021/8/12
 */
@Getter
@AllArgsConstructor
public class MemberInfo {
    /**
     * 常量池
     */
    private ConstantPool constantPool;
    /**
     * 访问标识 无符号 u2
     */
    private short accessFlags;
    /**
     * 名字索引 无符号 u2
     */
    private short nameIndex;
    /**
     * 描述索引 无符号 u2
     */
    private short descriptorIndex;
    /**
     * 属性数组
     */
    private AttributeInfo[] attributes;

    /**
     * 读取成员数组
     *
     * @param reader       类读取器
     * @param constantPool 常量池对象
     * @return 成员信息数组
     */
    public static MemberInfo[] readMembers(ClassReader reader, ConstantPool constantPool) {
        int num = reader.readU2ToUnsignedShort();
        MemberInfo[] memberInfos = new MemberInfo[num];
        for (int i = 0; i < num; i++) {
            memberInfos[i] = readMember(reader, constantPool);
        }
        return memberInfos;
    }

    /**
     * 读取成员信息
     *
     * @param reader       类读取器
     * @param constantPool 常量池对象
     * @return 成员信息
     */
    private static MemberInfo readMember(ClassReader reader, ConstantPool constantPool) {
        return new MemberInfo(
                constantPool,
                reader.readU2ToShort(),
                reader.readU2ToShort(),
                reader.readU2ToShort(),
                readAttributes(reader, constantPool)
        );
    }

    /**
     * 读取属性信息数组
     *
     * @param reader       类读取器
     * @param constantPool 常量池
     * @return 属性信息数组
     */
    public static AttributeInfo[] readAttributes(ClassReader reader, ConstantPool constantPool) {
        int num = reader.readU2ToUnsignedShort();
        AttributeInfo[] attributeInfos = new AttributeInfo[num];
        for (int i = 0; i < num; i++) {
            attributeInfos[i] = readAttribute(reader, constantPool);
        }
        return attributeInfos;
    }

    /**
     * 读取属性信息
     * readAttribute（）先读取属性名索引，根据它从常量池中找到属性名，
     * 然后读取属性长度，接着调用newAttributeInfo（）函数创建具体的属性实例
     * @param reader 类读取器
     * @param constantPool 常量池
     * @return 属性信息
     */
    private static AttributeInfo readAttribute(ClassReader reader, ConstantPool constantPool) {
        // 读取名称索引
        int nameIndex = reader.readU2ToUnsignedShort();
        String name = constantPool.getUtf8(nameIndex);
        // 读取属性长度
        int length = reader.readU4ToInt();
        AttributeInfo attributeInfo = AttributeFactory.newAttributeInfo(name, length, constantPool, nameIndex);
        attributeInfo.readInfo(reader);
        return attributeInfo;
    }

    /**
     * 名称
     *
     * @return 名称
     */
    public String name() {
        return this.constantPool.getUtf8(this.nameIndex);
    }

    /**
     * 描述信息
     *
     * @return 描述信息
     */
    public String descriptor() {
        return this.constantPool.getUtf8(this.descriptorIndex);
    }

    /**
     * 代码属性
     * @return 代码属性
     */
    public CodeAttribute codeAttribute() {
        for (AttributeInfo attribute : attributes) {
            if (AttributeFactory.CODE.equals(attribute.name())) {
                return (CodeAttribute) attribute;
            }
        }
        return null;
    }

    /**
     * 属性值
     * @return 属性值
     */
    public ConstantValueAttribute valueAttribute() {
        for (AttributeInfo attribute : attributes) {
            if (AttributeFactory.CONSTANT_VALUE.equals(attribute.name())) {
                return (ConstantValueAttribute) attribute;
            }
        }
        return null;
    }

}


















